package org.springblade.modules.api.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springblade.common.constant.RedisKeyConstant;
import org.springblade.common.exception.TrainingServiceException;
import org.springblade.common.utils.CommonUtil;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.modules.api.vo.ApiDept;
import org.springblade.modules.api.vo.ApiOaUser;
import org.springblade.modules.api.vo.ApiUserInfo;
import org.springblade.modules.api.vo.UserDeptModel;
import org.springblade.modules.personal.entity.UserBaseEntity;
import org.springblade.modules.personal.service.IUserBaseService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ApiServiceImpl implements ApiService {

	@Autowired
	private  RestTemplate restTemplate;
	@Autowired
	private  BladeRedis bladeRedis;
	@Autowired
	private  IUserBaseService userBaseService;
	@Autowired
	private IUserService userService;
	@Autowired
	private CommonUtil commonUtil;

	@Value("${jxc.sso.appId}")
	private String appId;
	@Value("${jxc.sso.appSecure}")
	private String appSecure;
	@Value("${jxc.sso.userInfoUrl}")
	private String userInfoUrl;
	@Value("${jxc.oaUser}")
	private String oaUserUrl;
	@Value("${jxc.dept}")
	private String deptUrl;
	@Value("${jxc.sso.logoutUrl}")
	private String logoutUrl;

	/**
	 * 根据ticker获取用户数据
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public ApiUserInfo getUserInfo(String ticket) {
//		String url = "https://dev.sso.4307.com/ctrl/userinfo/";
//		String url = "https://sso.4307.com/ctrl/userinfo/";
		//缺少证书 ，请求失败
		// 请求头（这里有一点需要注意，HttpHeaders和HttpEntity都是引入的spring的包）
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		// 请求
		MultiValueMap<String,Object> params=new LinkedMultiValueMap<>();
		params.add("ticket",ticket);
		params.add("type","simple");
		params.add("app_id",appId);
		params.add("app_secure",appSecure);
		HttpEntity<MultiValueMap<String,Object>> requst = new HttpEntity<>(params, headers);
//		ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requst, String.class);
		ignoreSSLVerification();
		ResponseEntity<String> responseEntity = restTemplate.postForEntity(userInfoUrl,  requst, String.class);
		JSONObject responseBody = JSON.parseObject(responseEntity.getBody());
		System.out.println("响应的结果:" + responseBody);
		ApiUserInfo apiUserInfo=new ApiUserInfo();
		String resoponsecode=String.valueOf(responseBody.get("code"));
		if ("50000".equals(resoponsecode)){//表示获取成功
			JSONObject data = (JSONObject) responseBody.get("data");
			apiUserInfo.setCardNo(String.valueOf(data.get("card_no")));
			apiUserInfo.setUserName(String.valueOf(data.get("user_name")));
			apiUserInfo.setToken(String.valueOf(data.get("token")));
			if (null==apiUserInfo.getCardNo() || null==apiUserInfo.getToken() ) throw new TrainingServiceException("登录异常,请重新登录");
			bladeRedis.set(RedisKeyConstant.JXC_SSO_TOKEN+apiUserInfo.getCardNo(),apiUserInfo.getToken());//存储token

			//检查是否有该用户，无则新增
			commonUtil.createUser(apiUserInfo.getCardNo(),String.valueOf(data.get("user_name")));
			return apiUserInfo;
		}
		if ("601004".equals(resoponsecode)){//表示Ticket已经被使用过

		}
		if ("601004".equals(resoponsecode)){//表示Ticket时间已过期

		}
		return apiUserInfo;
	}



	/**
	 * 需要忽略前，先调用此方法
	 * 忽略https证书验证
	 */
	public void ignoreSSLVerification(){
		try {
			TrustStrategy acceptingTrustStrategy = (chain, authType) -> true;
			SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);

			HttpClientBuilder clientBuilder = HttpClients.custom();

			CloseableHttpClient httpClient = clientBuilder.setSSLSocketFactory(sslsf).build();

			HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
			requestFactory.setHttpClient(httpClient);

			this.restTemplate = new RestTemplate(requestFactory);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	@Override
	public List<UserDeptModel> getUserDept() {
		List<UserDeptModel> depts=new ArrayList<>();
		List<ApiDept> apiDeptList = bladeRedis.get(RedisKeyConstant.JXC_DEPTS);
		//如果从缓存中拿不到，则初始化缓存
		if (CollectionUtils.isEmpty(apiDeptList)) apiDeptList=getApiDept();

		if (CollectionUtils.isNotEmpty(apiDeptList)){
			apiDeptList.forEach(apiDept -> {
				UserDeptModel userDeptModel =new UserDeptModel();
				userDeptModel.setValue(apiDept.getTags());
				userDeptModel.setLabel(apiDept.getText());
				//处理子集
				if ("true".equals(apiDept.getIsParent())){
					List<UserDeptModel> children=new ArrayList<>();
					if (CollectionUtils.isNotEmpty(apiDept.getNodes())){
						apiDept.getNodes().forEach(child->{
							UserDeptModel userDeptModelChild =new UserDeptModel();
							userDeptModelChild.setValue(child.getTags());
							userDeptModelChild.setLabel(child.getText());
							children.add(userDeptModelChild);
						});
					}
					userDeptModel.setChildren(children);
				}

				depts.add(userDeptModel);
			});
		}
		return depts;
	}

	@Override
	public boolean ssoLogout(Long userId) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		// 请求
		MultiValueMap<String,Object> params=new LinkedMultiValueMap<>();

		UserBaseEntity userBaseEntity = userBaseService.getOne(Wrappers.<UserBaseEntity>query().lambda().eq(UserBaseEntity::getUserId, userId));
		if (null==userBaseEntity)return false;
		String ssoToken=bladeRedis.get(RedisKeyConstant.JXC_SSO_TOKEN+userBaseEntity.getIdCard());
		params.add("app_id",appId);
		params.add("app_secure",appSecure);
		params.add("token",ssoToken);
		HttpEntity<MultiValueMap<String,Object>> requst = new HttpEntity<>(params, headers);
//		ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requst, String.class);
		ignoreSSLVerification();
		ResponseEntity<String> responseEntity = restTemplate.postForEntity(logoutUrl,  requst, String.class);
		log.info("响应的结果:" + responseEntity.getBody());

		String body = responseEntity.getBody();
		Integer resultCode= (Integer) JSONObject.parseObject(body).get("code");
//		bladeRedis.del(RedisKeyConstant.JXC_SSO_TOKEN+userBaseEntity.getIdCard());//删除登录缓存
		if (50000==resultCode){
			return true;
		}

		return false;
	}

	@Override
	public List<ApiDept> getApiDept() {
		List<ApiDept> depts = new ArrayList<>();
		try {
			ResponseEntity<String> reoponse = restTemplate.getForEntity(deptUrl, String.class);
			JSONObject responseBody = JSON.parseObject(reoponse.getBody());

			JSONArray dataArray= (JSONArray) responseBody.get("data");
			if (CollectionUtils.isNotEmpty(dataArray)) {
				JSONObject o =JSON.parseObject(dataArray.get(0)+"") ;
				JSONArray jsonArray= (JSONArray) o.get("nodes");

				for (int i=0 ;i<jsonArray.size();i++){
					ApiDept apiDept=new ApiDept();
					JSONObject jsonObject=jsonArray.getJSONObject(i);

					apiDept.setText(jsonObject.get("text")+"");

					JSONArray tags = (JSONArray) jsonObject.get("tags");
					apiDept.setTags(tags.get(0)+"");
					apiDept.setIsFirst(jsonObject.get("isFist")+"");
					apiDept.setIsParent(jsonObject.get("isParent")+"");

					//处理子项
					JSONArray childJsonArray= (JSONArray) jsonObject.get("nodes");
					if (CollectionUtils.isNotEmpty(childJsonArray)){
						List<ApiDept> childArray=new ArrayList<>();
						for (int j=0 ;j<childJsonArray.size();j++) {
							ApiDept apiDeptChild = new ApiDept();
							JSONObject jsonObjectChild = childJsonArray.getJSONObject(j);

							apiDeptChild.setText(jsonObjectChild.get("text") + "");
							JSONArray childTags = (JSONArray) jsonObjectChild.get("tags");
							apiDeptChild.setTags(childTags.get(0) + "");
							apiDeptChild.setIsFirst(jsonObjectChild.get("isFist") + "");
							apiDeptChild.setIsParent(jsonObjectChild.get("isParent") + "");
							childArray.add(apiDeptChild);
						}
						apiDept.setNodes(childArray);
					}
					depts.add(apiDept);

				}
				bladeRedis.set(RedisKeyConstant.JXC_DEPTS,depts);//将组织机构 部门-分厂 放入缓存
			}
		} catch (Exception e) {
			log.info(e.getMessage());
		}
		return depts;
	}


	@Override
	public List<ApiOaUser> getApiJxcUser()  {
		List<ApiOaUser> userList = new ArrayList<>();
		Map<String ,ApiOaUser> newCacehMap=new HashMap<>();// 即将存入缓存中的

		//缓存中的旧OA列表数据
		Map<String ,ApiOaUser> oaUsersOldCacheMap = bladeRedis.get(RedisKeyConstant.JXC_OA_USER);
		if (null==oaUsersOldCacheMap) oaUsersOldCacheMap=new HashMap<>();

		try {
			ResponseEntity<String> reoponse = restTemplate.getForEntity(oaUserUrl, String.class);
			JSONObject responseBody = JSON.parseObject(reoponse.getBody());
			JSONObject data= (JSONObject) responseBody.get("data");
			if (null!=data) {
				JSONObject o =JSON.parseObject(data.toJSONString()) ;
				JSONArray jsonArray = (JSONArray) o.get("data");
				for (int i=0;i<jsonArray.size();i++){
					ApiOaUser oaUser=new ApiOaUser();
					JSONObject jsonObject=jsonArray.getJSONObject(i);
					String idcard=String.valueOf(jsonObject.get("staff_card_no"));
					String userName = String.valueOf(jsonObject.get("user_name"));

					oaUser.setUser_name(userName);
					oaUser.setStaff_card_no(idcard);
					oaUser.setDept_id(String.valueOf(jsonObject.get("dept_id")));

					newCacehMap.put(idcard,oaUser);
					ApiOaUser oldOaUser = oaUsersOldCacheMap.get(idcard);
					if (null==oldOaUser) commonUtil.createUser(idcard,userName);//如果没有，则新增
					if (!Objects.equals(oldOaUser, oaUser)){//如果有，但是用户数据有区别，则修改
						UserBaseEntity userBaseEntity = userBaseService.selectByIdcard(idcard);
						userBaseEntity.setDeptId(oaUser.getDept_id());
						userBaseEntity.setUserName(oaUser.getUser_name());
						userBaseService.updateById(userBaseEntity);
					}
					userList.add(oaUser);
				}
				log.info("用户列表数量:"+userList.size());
				if (CollectionUtils.isNotEmpty(userList)) {
					List<String> userIdsList = userList.stream().map(ApiOaUser::getUid).collect(Collectors.toList());//后续改成身份证;
					bladeRedis.set(RedisKeyConstant.JXC_OA_USER_IDS,userIdsList);//将用户的标识集存入缓存中
					bladeRedis.set(RedisKeyConstant.JXC_OA_USER,newCacehMap);
				}
			}
		} catch (Exception e) {
			log.info("异常日志:"+e.getMessage());
		}

		return userList.stream().limit(20).collect(Collectors.toList());
	}


	@Override
	public boolean getSsoTokenStatus(String idCard) {
//		String url = "https://dev.sso.4307.com/ctrl/userinfo/";
//		String url = "https://sso.4307.com/ctrl/userinfo/";
		//缺少证书 ，请求失败
		// 请求头（这里有一点需要注意，HttpHeaders和HttpEntity都是引入的spring的包）
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		// 请求
		MultiValueMap<String,Object> params=new LinkedMultiValueMap<>();
		String ssoToken  = bladeRedis.get(RedisKeyConstant.JXC_SSO_TOKEN+idCard);
		if (StringUtils.isEmpty(ssoToken)) return false;
		params.add("token",ssoToken);
		params.add("type","simple");
		params.add("app_id",appId);
		params.add("app_secure",appSecure);
		HttpEntity<MultiValueMap<String,Object>> requst = new HttpEntity<>(params, headers);
		ignoreSSLVerification();
		ResponseEntity<String> responseEntity = restTemplate.postForEntity(userInfoUrl,  requst, String.class);
		JSONObject responseBody = JSON.parseObject(responseEntity.getBody());
		System.out.println("响应的结果:" + responseBody);
		String resoponsecode=String.valueOf(responseBody.get("code"));
//		if ("601010".equals(resoponsecode)){//表示登录已注销
//
//		}
		if (!"50000".equals(resoponsecode)){//表示登录不正常  sso那边已注销
//			bladeRedis.del(RedisKeyConstant.JXC_SSO_TOKEN+idCard);
			return false;
		}
		return true;//表示登录正常
	}
}
